package grape.sequence.service.generator.impl;

import cn.hutool.json.JSONUtil;
import grape.base.rest.client.dict.DictClient;
import grape.base.service.dict.po.Dict;
import grape.common.exception.runtime.RDataNotExistException;
import grape.common.tools.ToolService;
import grape.sequence.service.config.api.IConfigService;
import grape.sequence.service.config.po.Config;
import grape.sequence.service.generator.param.SequenceConfigParam;
import grape.sequence.service.generator.periodparser.IPeriodUnitParser;
import grape.sequence.service.generator.dbbased.ISequenceDatabaseTypeGenerator;
import grape.sequence.service.generator.api.ISequenceGenerator;
import grape.sequence.service.generator.servicemapper.ConfigServiceMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Created by yangwei
 * Created at 2020/8/20 18:48
 */
@Slf4j
@Service
public class SequenceGeneratorImpl implements ISequenceGenerator, ToolService {

    @Autowired
    private IConfigService iConfigService;

    @Autowired
    private List<IPeriodUnitParser> iPeriodUnitParsers;
    @Autowired
    private List<ISequenceDatabaseTypeGenerator> sequenceDatabaseTypeGenerators;

    @Autowired
    private DictClient dictClient;
    @Autowired
    private ConfigServiceMapper configServiceMapper;

    /**
     * 数据库类型，mysql,oracle,不配置默认为mysql
     */
    @Value("${grape.sequence.generator.database-type:}")
    private String databaseType;

    @Override
    public String nextSeqValueByConfigCode(String configCode) {
        assertParamNotEmpty(configCode,"configCode不能为空");
        Config config = iConfigService.getByCode(configCode);
        if (config == null) {
            throw new RDataNotExistException("根据序列配置编码查询configCode=" + configCode + "数据不存在");
        }

        return nextSeqValueByConfig(config);
    }

    @Override
    public String nextSeqValueByConfigId(String configId) {

        return nextSeqValueByConfig(getConfigById(configId));
    }

    /**
     * 根据id获取配置信息
     * @param configId
     * @return
     */
    private Config getConfigById(String configId) {
        assertParamNotEmpty(configId,"configId不能为空");
        Config config = iConfigService.getById(configId);
        if (config == null) {
            throw new RDataNotExistException("根据序列配置id查询configId=" + configId + "数据不存在");
        }
        return  config;
    }
    @Override
    public String currentSeqValueByConfigId(String configId) {
        Config config = getConfigById(configId);
        SequenceConfigParam sequenceConfigParam = configServiceMapper.configToParam(config);
        IPeriodUnitParser.ParserResult suffixByConfig = getSuffixByConfig(config);
        sequenceConfigParam.setPeriod(suffixByConfig.getPeriod());
        return currentSeqValueFree(config.getCode() + "_" + suffixByConfig.getFull(),sequenceConfigParam);
    }

    /**
     * 配置配置信息周期获取表后缀
     * @param config
     * @return [code]_[根据周期获取的后缀]
     */
    private IPeriodUnitParser.ParserResult getSuffixByConfig(Config config) {
        Dict periodUnitDict = dictClient.getDictById(config.getPeriodUnitDictId());
        Config.PeriodUnitDictItem periodUnitDictItem = null;
        for (Config.PeriodUnitDictItem value : Config.PeriodUnitDictItem.values()) {
            if(value.name().equals(periodUnitDict.getCode())){
                periodUnitDictItem = value;
            }
        }

        for (IPeriodUnitParser iPeriodUnitParser : iPeriodUnitParsers) {
            IPeriodUnitParser.ParserResult parserResult = iPeriodUnitParser.parse(config,periodUnitDictItem);
            if(parserResult != null){
                return parserResult;
            }
        }
        throw new RDataNotExistException("配置不正确，未找到对应的周期解析器，config=[{}]", JSONUtil.toJsonStr(config));

    }

    /**
     * 内部方法，根据配置信息获取下一个值
     * @param config
     * @return
     */
    private String nextSeqValueByConfig(Config config) {
        IPeriodUnitParser.ParserResult suffixByConfig = getSuffixByConfig(config);
        SequenceConfigParam sequenceConfigParam = configServiceMapper.configToParam(config);
        sequenceConfigParam.setPeriod(suffixByConfig.getPeriod());
        return nextSeqValueFree(config.getCode() + "_"+suffixByConfig.getFull(),sequenceConfigParam);

    }
    @Override
    public String nextSeqValueDefault(String suffix) {
        SequenceConfigParam param = new SequenceConfigParam();
        param.setStartValue(1);
        param.setStepValue(1);
        return nextSeqValueFree(suffix,null);
    }

    @Override
    public String nextSeqValueFree(String suffix, SequenceConfigParam param) {
        assertParamNotEmpty(suffix,"suffix不能为空");
        assertParamNotNull(param,"param不能为空");
        ISequenceDatabaseTypeGenerator.SequenceResult result = null;
        for (ISequenceDatabaseTypeGenerator sequenceDatabaseTypeGenerator : sequenceDatabaseTypeGenerators) {
            if (sequenceDatabaseTypeGenerator.support(databaseType)) {
                result = sequenceDatabaseTypeGenerator.nextSeqValue(suffix,param.getStartValue(),param.getStepValue());
                if (result == null) {
                    throw new RuntimeException("生成序列失败,当前生成器=["+ sequenceDatabaseTypeGenerator.getClass().getName() +"]");
                }
                break;
            }
        }
        if (result == null) {
            throw new RuntimeException("配置错误，生成序列失败,没有可用的生成器databaseType=" + databaseType+",可配置项grape.sequence.generator.database-type,默认mysql,当前仅支持mysql数据库");
        }
        if (result.isFirst() && !isStrEmpty(param.getConfigId())) {
            // 更新每一次生成的时间
            Config config = new Config();
            config.setId(param.getConfigId());
            config.setFirstGenerateAt(System.currentTimeMillis());
            iConfigService.updateById(config);
        }
        return wrapResult(result.getNextValue(),param);
    }

    @Override
    public String currentSeqValueFree(String suffix, SequenceConfigParam param) {
        assertParamNotEmpty(suffix,"suffix不能为空");
        assertParamNotNull(param,"param不能为空");
        String result = null;
        for (ISequenceDatabaseTypeGenerator sequenceDatabaseTypeGenerator : sequenceDatabaseTypeGenerators) {
            if (sequenceDatabaseTypeGenerator.support(databaseType)) {
                result = sequenceDatabaseTypeGenerator.currentSeqValue(suffix);
                break;
            }
        }
        return wrapResult(result,param);
    }

    /**
     * 根据配置规则，将获取的原始数字id包括
     * @param nextValue
     * @param param
     * @return
     */
    private String wrapResult(String nextValue,SequenceConfigParam param){
        String result = nextValue;
        // 根据配置处理返回结果
        if (!isStrEmpty(result) ) {
            // 补充长度
            if(param.getMinLength() != null && param.getMinLength() >0 && !isStrEmpty(param.getPrepend())){

                int length = param.getMinLength() - result.length();
                for (int i = 0; i < length; i++) {
                    result = param.getPrepend() + result;
                    // 如果prepend是多个字符，这里不能循环多次，判断一下
                    if(result.length() >= param.getMinLength()){
                        break;
                    }
                }
            }
            // 补充前缀
            if (!isStrEmpty(param.getPrefix())) {
                String prefix = param.getPrefix();
                if (param.getIsPrefixWithPeriod() != null && param.getIsPrefixWithPeriod() && !isStrEmpty(param.getPeriod())) {
                    prefix += param.getPeriod();
                }
                result = prefix + result;
            }

        }
        return result;
    }
}
